home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / mach / amiga / scsi9091.lzh / device.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-02-24  |  12.1 KB  |  553 lines

  1. #include <exec/types.h>
  2. #include <exec/execbase.h>
  3. #include <exec/nodes.h>
  4. #include <exec/resident.h>
  5. #include <exec/errors.h>
  6. #include <libraries/expansionbase.h>
  7. #include <libraries/configvars.h>
  8. #include <devices/trackdisk.h>
  9.  
  10. /*
  11.  * Set SysBase to a local variable, that loads directly from 4 when it
  12.  * has to be reloaded
  13.  */
  14. #define BASE_EXT_DECL
  15. #define BASE_NAME (*(void **)4)
  16. #include <inline/exec.h>
  17. #undef PRIVATE
  18. #define BASE_EXT_DECL
  19. #define BASE_PAR_DECL void *ExpansionBase,
  20. #define BASE_PAR_DECL0 void *ExpansionBase
  21. #include <inline/expansion.h>
  22.  
  23. #include <stddef.h>
  24.  
  25. #include "device.h"
  26.  
  27. extern void scsi_cmd();
  28.  
  29. ulong func_table[];
  30. struct init_struct data_table;
  31. struct scsi_dev *init_routine();
  32. /*
  33.  * small assembly glue.. needed, because these routines have to preserve ALL
  34.  * registers.. 
  35.  */
  36. extern ulong glue_init(), glue_scsi_expunge(), glue_scsi_open(), 
  37.        glue_scsi_close(), glue_scsi_beginio(), glue_scsi_abortio();
  38. DECL_DPRINTF;
  39. extern void try_unit (struct scsi_dev *dev, int unit);
  40. int expunge_unit (struct scsi_dev *dev, struct scsi_unit *unit);
  41.  
  42. ulong Init[] = {
  43.   sizeof(struct scsi_dev),
  44.   (ulong) func_table,
  45.   (ulong) &data_table,
  46.   (ulong) glue_init,
  47. };
  48.  
  49. int scsi_open(), scsi_close(), scsi_expunge(), 
  50.     scsi_beginio(), scsi_abortio(), null_func();
  51.  
  52. ulong func_table[] = {
  53.   (ulong) glue_scsi_open,
  54.   (ulong) glue_scsi_close,
  55.   (ulong) glue_scsi_expunge,
  56.   (ulong) null_func,
  57.   (ulong) glue_scsi_beginio,
  58.   (ulong) glue_scsi_abortio,
  59.   ~0,
  60. };
  61.  
  62. struct init_struct {
  63.   DECLARE_BYTE(1); DECLARE_LONG(2); DECLARE_BYTE(3); DECLARE_WORD(4);
  64.   DECLARE_WORD(5); DECLARE_LONG(6); 
  65.   ubyte end[4];
  66. } data_table = {
  67.   INITBYTE( offsetof(struct Node, ln_Type), NT_DEVICE ),
  68.   INITLONG( offsetof(struct Node, ln_Name), SCSI_NAME ),
  69.   INITBYTE( offsetof(struct Library, lib_Flags), LIBF_SUMUSED|LIBF_CHANGED ),
  70.   INITWORD( offsetof(struct Library, lib_Version), SCSI_VERSION ),
  71.   INITWORD( offsetof(struct Library, lib_Revision), SCSI_REVISION ),
  72.   INITLONG( offsetof(struct Library, lib_IdString), SCSI_IDSTRING ),
  73.   0,0,0,0,
  74. };  
  75.  
  76. /*
  77.  * those glue functions just save the trashed registers on the stack and
  78.  * call the appropriate function with the set up argument(s)
  79.  * Pitty gas doesn't accept comments.. or I was to stupid to guess the
  80.  * correct syntax:-))
  81.  */
  82. asm("
  83. .text
  84.     .globl _glue_init
  85. _glue_init:
  86.     moveml #0x7ffc,sp@-
  87.  
  88.     moveml #0x8080,sp@-
  89.     jsr _init_routine
  90.     addw   #8,sp
  91.  
  92.     moveml sp@+,#0x3ffe
  93.         rts
  94.  
  95.     .globl _glue_scsi_open
  96. _glue_scsi_open:
  97.     moveml #0x7ffc,sp@-
  98.  
  99.     jsr _scsi_open
  100.  
  101.     moveml sp@+,#0x3ffe
  102.     rts
  103.  
  104.     .globl _glue_scsi_close
  105. _glue_scsi_close:
  106.     moveml #0x7ffc,sp@-
  107.  
  108.     jsr _scsi_close
  109.  
  110.     moveml sp@+,#0x3ffe
  111.     rts
  112.  
  113.  
  114.     .globl _glue_scsi_expunge
  115. _glue_scsi_expunge:
  116.     moveml #0x7ffc,sp@-
  117.  
  118.     jsr _scsi_expunge
  119.  
  120.     moveml sp@+,#0x3ffe
  121.     rts
  122.  
  123.     .globl _glue_scsi_beginio
  124. _glue_scsi_beginio:
  125.     moveml #0x7ffc,sp@-
  126.  
  127.     jsr _scsi_beginio
  128.  
  129.     moveml sp@+,#0x3ffe
  130.     rts
  131.  
  132.     .globl _glue_scsi_abortio
  133. _glue_scsi_abortio:
  134.     moveml #0x7ffc,sp@-
  135.  
  136.     jsr _scsi_abortio
  137.  
  138.     moveml sp@+,#0x3ffe
  139.     rts
  140. ");
  141.  
  142. struct scsi_dev *
  143. init_routine(struct scsi_dev *dev, ulong seg_list, volatile ulong a1)
  144. {
  145.   struct ConfigDev *cd;
  146.   struct MsgPort *mp;
  147.   struct Task *tcb;
  148.   int unit;
  149.   struct ExpansionBase *ExpansionBase;
  150.  
  151. DPRINTF(("init ($%lx): seglist=$%lx, dev=$%lx", init_routine, seg_list, dev));
  152.  
  153.   dev->sc_seglist = seg_list;
  154.  
  155.   mp = &dev->sc_msgport;
  156.   mp->mp_Node.ln_Type = NT_MSGPORT;
  157.   mp->mp_SigBit = AllocSignal(-1);
  158.   mp->mp_SigTask = FindTask(0);
  159.   mp->mp_Flags = PA_SIGNAL;
  160.   NewList(&mp->mp_MsgList);
  161.  
  162.   InitSemaphore(& dev->sc_semaph);
  163.   /* 
  164.    * This will take care, that - while we're waiting later - Init won't 
  165.    * be interrupted by an OpenDevice call... 
  166.    */
  167.   ObtainSemaphore(& dev->sc_semaph);
  168.  
  169.   if (ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library",0))
  170.     {
  171.       /*
  172.        * using FindConfigDev() instead of GetCurrentBinding() ensures,
  173.        * that these units can be mounted without having been initialized
  174.        * by Binddrivers.. the first mount will init the device 
  175.        */
  176.       cd = FindConfigDev(ExpansionBase, 0, BOARD_MANUFACT, BOARD_PROCUCT);
  177.  
  178.       if (cd)
  179.     {
  180.       dev->sc_base = (ulong)cd->cd_BoardAddr;
  181.       cd->cd_Flags &= ~CDF_CONFIGME;
  182.  
  183.       /*
  184.        * now fire up the handler task, that will execute our 
  185.        * scsi command requests for us (message queues are an excellent
  186.        * way of garanteeing single-threaded device hardware usage.. ) 
  187.        */
  188.       
  189.       tcb = &dev->sc_htcb;
  190.       tcb->tc_SPLower = (APTR)dev->sc_hstack;
  191.       tcb->tc_SPUpper = (APTR)(dev->sc_hstack + HANDLER_STACKSIZE);
  192.       tcb->tc_SPReg = (APTR)((ulong)tcb->tc_SPUpper - 4);
  193.       /* pass the child the device pointer */
  194.       *(struct scsi_dev **)tcb->tc_SPReg = dev;
  195.       
  196.       tcb->tc_Node.ln_Type = NT_TASK;        
  197.       tcb->tc_Node.ln_Pri = HANDLER_PRIORITY;
  198.       tcb->tc_Node.ln_Name = HANDLER_NAME;
  199.       
  200.       NewList(&tcb->tc_MemEntry);
  201.  
  202. DPRINTF(("starting handler task"));
  203.       AddTask(tcb, scsi_cmd, 0);
  204.       
  205.       /*
  206.        * wait for child to get ready.. don't know, how bad this is
  207.        * at this point to wait - it *is* bad according to the RKM - 
  208.        * but how bad.....?? 
  209.        */
  210.       WaitPort(&dev->sc_msgport); GetMsg(&dev->sc_msgport);
  211.       /* when this returns, dev->sc_hmsgport will be valid */
  212.  
  213. DPRINTF(("Handler task ok"));
  214.       
  215.       /* 
  216.        * Now try to find out, which devices are connected to
  217.        * the SCSI bus, and fire up the respective units, that mount
  218.        * themselves as DOS nodes (not at the moment:-)) 
  219.        */
  220.       for (unit = 0; unit < 7; unit++) try_unit (dev, unit);
  221.     }
  222.       CloseLibrary(ExpansionBase);
  223.     }
  224. DPRINTF(("scsi_init terminated"));
  225.   ReleaseSemaphore(& dev->sc_semaph);
  226.   return dev;
  227. }
  228.  
  229. int
  230. scsi_open()
  231. {
  232.   /* can't use them as regular variables, because d0/a1 are likely to
  233.    * get used as temporary registers */
  234.   register struct scsi_dev *dev_pass asm("a6");
  235.   register struct IORequest *io_req_pass asm("a1");
  236.   register int unit_pass asm("d0");
  237.  
  238.   struct scsi_dev *dev = dev_pass;
  239.   struct IORequest *io_req = io_req_pass;
  240.   int unit = unit_pass;
  241.   
  242.   /*
  243.    * we will only be able to get this semaphore, when Init is completely
  244.    * thru with its job, this was necessary, because Init breaks the Forbid
  245.    * Exec enabled during its execution 
  246.    */
  247.   ObtainSemaphore(& dev->sc_semaph);
  248.  
  249. DPRINTF(("open: dev = $%lx, unit# = %ld, io_req = $%lx", dev, unit, io_req));
  250.  
  251.   /* perform validity checking on the unit range */
  252.   if (unit >= 0 && unit <= 6)
  253.     {
  254.       /*
  255.        * since we already fired up all units that exist, if the requested
  256.        * unit doesn't have a corresponding unit task, we return with 
  257.        * an error 
  258.        */
  259.       if (dev->sc_units[unit])
  260.         {
  261.       ++ dev->sc_device.dd_Library.lib_OpenCnt;
  262.       ++ dev->sc_units[unit]->scu_unit.unit_OpenCnt;
  263.       io_req->io_Error = 0;
  264.       io_req->io_Unit = (struct Unit *)dev->sc_units[unit];
  265.       dev->sc_device.dd_Library.lib_Flags &= ~LIBF_DELEXP;
  266. DPRINTF(("open-ok!"));
  267.        ReleaseSemaphore(& dev->sc_semaph);
  268.       return 0;
  269.     }
  270.     }
  271. DPRINTF(("open-Error!"));
  272.   ReleaseSemaphore(& dev->sc_semaph);
  273.   io_req->io_Error = IOERR_OPENFAIL;
  274.   return IOERR_OPENFAIL;
  275. }
  276.  
  277. int
  278. scsi_close()
  279. {
  280.   register struct scsi_dev *dev_pass asm("a6");
  281.   register struct IORequest *io_req_pass asm("a1");
  282.   struct IORequest *io_req = io_req_pass;
  283.   struct scsi_unit *su = (struct scsi_unit *)io_req->io_Unit;
  284.   struct scsi_dev *dev = dev_pass;
  285.  
  286. DPRINTF(("close: dev = $%lx, unit = $%lx, io_req = $%lx", dev,su,io_req));
  287.  
  288.   io_req->io_Unit = (void *)
  289.   io_req->io_Device = (void *)-1;
  290.   
  291.   if (-- su->scu_unit.unit_OpenCnt == 0)
  292.     expunge_unit(dev, su);
  293.     
  294.   if (-- dev->sc_device.dd_Library.lib_OpenCnt == 0)
  295.     {
  296.       if (dev->sc_device.dd_Library.lib_Flags & LIBF_DELEXP)
  297.         return scsi_expunge(dev);
  298.     }
  299.   return 0;
  300. }
  301.  
  302. int
  303. scsi_expunge()
  304. {
  305.   register struct scsi_dev *dev_pass asm("a6");
  306.   struct scsi_dev *dev = dev_pass;
  307.   ulong seglist;
  308.  
  309. DPRINTF(("expunge: dev = $%lx", dev));
  310.  
  311. #ifdef DO_EXPUNGE
  312.  
  313.   if (dev->sc_device.dd_Library.lib_OpenCnt > 0)
  314.     {
  315.       dev->sc_device.dd_Library.lib_Flags |= LIBF_DELEXP;
  316.       return 0;
  317.     }
  318.  
  319.   dev->sc_hmessage.scm_cmd = SCM_CMD_SHUTDOWN;
  320.   PutGetMsg(dev->sc_hmsgport, &dev->sc_msgport, 
  321.         (struct Message *)&dev->sc_hmessage);
  322.   /* handler task now shut down */
  323.   
  324.   Remove((struct Node *)dev);
  325.  
  326.   seglist = dev->sc_seglist;
  327.  
  328.   FreeMem(dev,
  329.       dev->sc_device.dd_Library.lib_NegSize +
  330.           dev->sc_device.dd_Library.lib_PosSize);
  331.   return seglist;
  332. #else
  333.   
  334.   return 0;
  335. #endif
  336.  
  337. }
  338.  
  339. int
  340. null_func()
  341. {
  342.   return 0;
  343. }
  344.  
  345. int
  346. expunge_unit(struct scsi_dev *dev, struct scsi_unit *unit)
  347. {
  348.   /* since I spawned the units at Init-time, not at Open-time, I don't
  349.    * want to get rid of them now.. */
  350.   return 0;
  351. }
  352.  
  353. /****************************************************************************/
  354.  
  355. int scsi_invalid(), scsi_reset(),
  356.     scsi_read(), scsi_write(), scsi_update(), scsi_clear(), scsi_stop(),
  357.     scsi_start(), scsi_flush(), scsi_motor(), scsi_seek(), scsi_format(),
  358.     scsi_remove(), scsi_changenum(), scsi_changestate(), scsi_protstatus(),
  359.     scsi_rawread(), scsi_rawwrite(), scsi_getdrivetype(), 
  360.     scsi_getnumtracks(), scsi_addchangeint(), scsi_remchangeint(),
  361.     scsi_direct();
  362.  
  363. int
  364. (*cmd_table []) () = {
  365.     scsi_invalid,    /* 00 */
  366.     scsi_reset,        /* 01 */
  367.     scsi_read,        /* 02 */
  368.     scsi_write,        /* 03 */
  369.     scsi_update,    /* 04 */
  370.     scsi_clear,        /* 05 */
  371.     scsi_stop,        /* 06 */
  372.     scsi_start,        /* 07 */
  373.     scsi_flush,        /* 08 */
  374.     scsi_motor,        /* 09 */
  375.     scsi_seek,        /* 10 */
  376.     scsi_format,    /* 11 */
  377.     scsi_remove,    /* 12 */
  378.     scsi_changenum,    /* 13 */
  379.     scsi_changestate,    /* 14 */
  380.     scsi_protstatus,    /* 15 */
  381.     scsi_rawread,    /* 16 */
  382.     scsi_rawwrite,    /* 17 */
  383.     scsi_getdrivetype,    /* 18 */
  384.     scsi_getnumtracks,    /* 19 */
  385.     scsi_addchangeint,    /* 20 */
  386.     scsi_remchangeint,    /* 21 */
  387.     scsi_invalid,    /* 22 */
  388.     scsi_invalid,    /* 23 */
  389.     scsi_invalid,    /* 24 */
  390.     scsi_invalid,    /* 25 */
  391.     scsi_invalid,    /* 26 */
  392.     scsi_invalid,    /* 27 */
  393.     scsi_direct,    /* 28 */
  394. };
  395.     
  396. int
  397. scsi_beginio()
  398. {
  399.   register struct IORequest *io_req_pass asm("a1");
  400.   register struct scsi_dev *dev_pass asm("a6");
  401.   struct scsi_dev *dev = dev_pass;
  402.   struct IORequest *io_req = io_req_pass;
  403.   struct scsi_unit *su = (struct scsi_unit *)io_req->io_Unit;
  404.  
  405.   if (!su) return IOERR_OPENFAIL;
  406.  
  407. DPRINTF(("beginio: dev = $%lx, unit# = %ld, cmd = %ld",
  408.      dev, su->scu_unitnum, io_req->io_Command));
  409.   
  410.   /*
  411.    * in the first release of the device, the RMB bit is ignored, and
  412.    * thus removeable mediums are not supported. To be compatible to
  413.    * later releases, ETD-commands are just routed to their normal
  414.    * partners.. 
  415.    */
  416.    
  417.   io_req->io_Command &= ~TDF_EXTCOM;
  418.   io_req->io_Message.mn_Node.ln_Type = NT_MESSAGE;
  419.  
  420.   if (io_req->io_Command >= 0 && io_req->io_Command <= 28)
  421.     {
  422.       /* no immediates supported for now.. */
  423.       io_req->io_Flags &= ~IOF_QUICK;
  424.       PutMsg(su->scu_cmd_mp, (struct Message *)io_req);
  425.       return 0;
  426.     }
  427.   return IOERR_NOCMD;
  428. }
  429.  
  430. int
  431. scsi_abortio()
  432. {
  433.   return IOERR_NOCMD;
  434. }
  435.  
  436. /* now follow all - so far - ignored commands */
  437.  
  438. int
  439. scsi_invalid()
  440. {
  441.   return IOERR_NOCMD;
  442. }
  443.  
  444. int
  445. scsi_reset()
  446. {
  447.   return IOERR_NOCMD;
  448. }
  449.  
  450. int
  451. scsi_stop()
  452. {
  453.   return IOERR_NOCMD;
  454. }
  455. int
  456. scsi_start()
  457. {
  458.   return IOERR_NOCMD;
  459. }
  460.  
  461. int
  462. scsi_flush(struct IOStdReq *io_req)
  463. {
  464. #ifdef ENABLE_CACHE
  465.   invalidate_cache (io_req->io_Unit);
  466.   return 0;
  467. #endif
  468.   return IOERR_NOCMD;
  469. }
  470. int
  471. scsi_motor()
  472. {
  473.   return 0;
  474. }
  475. int
  476. scsi_seek()
  477. {
  478.   return IOERR_NOCMD;
  479. }
  480. int
  481. scsi_remove()
  482. {
  483.   return IOERR_NOCMD;
  484. }
  485.  
  486. int
  487. scsi_changenum(struct IOStdReq *io_req)
  488. {
  489.   io_req->io_Actual = 1; /* always disk label 1... */
  490.   return 0;
  491. }
  492. int
  493. scsi_changestate(struct IOStdReq *io_req)
  494. {
  495.   io_req->io_Actual = 0; /* always a disk present?? with RMB surely not... */
  496.   return 0;
  497. }
  498. int
  499. scsi_rawread()
  500. {
  501.   return IOERR_NOCMD;
  502. }
  503. int
  504. scsi_rawwrite()
  505. {
  506.   return IOERR_NOCMD;
  507. }
  508.  
  509. int
  510. scsi_getdrivetype(struct IOStdReq *io_req)
  511. {
  512.   io_req->io_Actual = DRIVE3_5;
  513.   return 0;
  514. }
  515.  
  516. int
  517. scsi_getnumtracks(struct IOStdReq *io_req)
  518. {
  519.   io_req->io_Actual = 1;
  520.   return 0;
  521. }
  522.  
  523. int
  524. scsi_clear(struct IOStdReq *io_req)
  525. {
  526. #ifdef ENABLE_CACHE
  527.   invalidate_cache (io_req->io_Unit);
  528.   return 0;
  529. #endif
  530.   return IOERR_NOCMD;
  531. }
  532.  
  533. int
  534. scsi_update()
  535. {
  536. #ifdef ENABLE_CACHE
  537.   return 0; /* we have a write-thru cache */
  538. #endif
  539.   return IOERR_NOCMD;
  540. }
  541.  
  542. int
  543. scsi_addchangeint()
  544. {
  545.   return IOERR_NOCMD;
  546. }
  547.  
  548. int
  549. scsi_remchangeint()
  550. {
  551.   return IOERR_NOCMD;
  552. }
  553.